<?php
/**
 * [WeEngine System] Copyright (c) 2014 WE7.CC
 * WeEngine is NOT a free software, it under the license terms, visited http://www.we7.cc/ for more details.
 */
define('IN_API', true);
require_once './framework/bootstrap.inc.php';
load()->model('reply');
load()->app('common');
load()->classs('wesession');
$hash = $_GPC['hash'];
if (!empty( $hash )) {
    $id = pdo_fetchcolumn("SELECT acid FROM " . tablename('account') . " WHERE hash = :hash", array( ':hash' => $hash ));
}
if (!empty( $_GPC['appid'] )) {
    $appid = ltrim($_GPC['appid'], '/');
    if ($appid == 'wx570bc396a51b8ff8') {
        $_W['account'] = array( 'type' => '3', 'key' => 'wx570bc396a51b8ff8', 'level' => 4, 'token' => 'platformtestaccount', );
    } else {
        $id = pdo_fetchcolumn("SELECT acid FROM " . tablename('account_wechats') . " WHERE `key` = :appid", array( ':appid' => $appid ));
    }
}
if (empty( $id )) {
    $id = intval($_GPC['id']);
}
if (!empty( $id )) {
    $_W['account'] = account_fetch($id);
}
if (empty( $_W['account'] )) {
    exit( 'initial error hash or id' );
}
if (empty( $_W['account']['token'] )) {
    exit( 'initial missing token' );
}
$_W['debug'] = intval($_GPC['debug']);
$_W['acid'] = $_W['account']['acid'];
$_W['uniacid'] = $_W['account']['uniacid'];
$_W['uniaccount'] = uni_fetch($_W['uniacid']);
$_W['account']['groupid'] = $_W['uniaccount']['groupid'];
$_W['account']['qrcode'] = $_W['attachurl'] . 'qrcode_' . $_W['acid'] . '.jpg?time=' . $_W['timestamp'];
$_W['account']['avatar'] = $_W['attachurl'] . 'headimg_' . $_W['acid'] . '.jpg?time=' . $_W['timestamp'];
$_W['modules'] = uni_modules();

$engine = new WeEngine();
if (!empty( $_W['setting']['copyright']['status'] )) {
    $engine->died('抱歉，站点已关闭，关闭原因：' . $_W['setting']['copyright']['reason']);
}
if (!empty( $_W['uniaccount']['endtime'] ) && TIMESTAMP > $_W['uniaccount']['endtime']) {
    $engine->died('抱歉，您的公众号已过期，请及时联系管理员');
}

if ($_W['isajax'] && $_W['ispost'] && $_GPC['flag'] == 1) {
    $engine->encrypt();
}
if ($_W['isajax'] && $_W['ispost'] && $_GPC['flag'] == 2) {
    $engine->decrypt();
}
load()->func('compat.biz');
$_W['isajax'] = false;
$engine->start();


class WeEngine {

    private $account = null;

    private $modules = array();

    public $keyword = array();

    public $message = array();


    public function __construct(){
        global $_W;
        $this->account = WeAccount::create($_W['account']);
        $this->modules = array_keys($_W['modules']);
        $this->modules[] = 'cover';
        $this->modules[] = 'default';
        $this->modules = array_unique($this->modules);
    }


    public function encrypt(){
        global $_W;
        if (empty( $this->account )) {
            exit( 'Miss Account.' );
        }
        $timestamp = TIMESTAMP;
        $nonce = random(5);
        $token = $_W['account']['token'];
        $signkey = array( $token, TIMESTAMP, $nonce, );
        sort($signkey, SORT_STRING);
        $signString = implode($signkey);
        $signString = sha1($signString);

        $_GET['timestamp'] = $timestamp;
        $_GET['nonce'] = $nonce;
        $_GET['signature'] = $signString;
        $postStr = file_get_contents('php://input');
        if (!empty( $_W['account']['encodingaeskey'] ) && strlen($_W['account']['encodingaeskey']) == 43 && !empty( $_W['account']['key'] ) && $_W['setting']['development'] != 1) {
            $data = $this->account->encryptMsg($postStr);
            $array = array( 'encrypt_type' => 'aes', 'timestamp' => $timestamp, 'nonce' => $nonce, 'signature' => $signString, 'msg_signature' => $data[0], 'msg' => $data[1], );
        } else {
            $data = array( '', '', );
            $array = array( 'encrypt_type' => '', 'timestamp' => $timestamp, 'nonce' => $nonce, 'signature' => $signString, 'msg_signature' => $data[0], 'msg' => $data[1], );
        }
        exit( json_encode($array) );
    }


    public function decrypt(){
        global $_W;
        if (empty( $this->account )) {
            exit( 'Miss Account.' );
        }
        $postStr = file_get_contents('php://input');
        if (!empty( $_W['account']['encodingaeskey'] ) && strlen($_W['account']['encodingaeskey']) == 43 && !empty( $_W['account']['key'] ) && $_W['setting']['development'] != 1) {
            $resp = $this->account->local_decryptMsg($postStr);
        } else {
            $resp = $postStr;
        }
        exit( $resp );
    }


    public function start(){
        global $_W;
        if (empty( $this->account )) {
            exit( 'Miss Account.' );
        }
        if (!$this->account->checkSign()) {
            exit( 'Check Sign Fail.' );
        }
        if (strtolower($_SERVER['REQUEST_METHOD']) == 'get') {
            $row = array();
            $row['isconnect'] = 1;
            pdo_update('account', $row, array( 'acid' => $_W['acid'] ));
            exit( htmlspecialchars($_GET['echostr']) );
        }
        if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
            $postStr = file_get_contents('php://input');
            if (!empty( $_GET['encrypt_type'] ) && $_GET['encrypt_type'] == 'aes') {
                $postStr = $this->account->decryptMsg($postStr);
            }
            WeUtility::logging('trace', $postStr);
            $message = $this->account->parse($postStr);

            $this->message = $message;
            //将用户地理位置插入到表中
//            $data = array(
//                'ToUserName'=>$message['to'],
//                'FromUserName'=>$message['from'],
//                'Createtime'=>$message['time'],
//                'MsgType'=>$message['type'],
//                'location_x'=>$message['location_x'],
//                'location_y'=>$message['location_y']
//            );
//            pdo_insert('user_location',$data);
            if (empty( $message )) {
                WeUtility::logging('waring', 'Request Failed');
                exit( 'Request Failed' );
            }
            $_W['openid'] = $message['from'];
            $_W['fans'] = array( 'from_user' => $_W['openid'] );
            $this->booking($message);
            if ($message['event'] == 'unsubscribe') {
                $this->receive(array(), array(), array());
                exit();
            }

            $sessionid = md5($message['from'] . $message['to'] . $_W['uniacid']);
            session_id($sessionid);
            WeSession::start($_W['uniacid'], $_W['openid']);

            $_SESSION['openid'] = $_W['openid'];
            $pars = $this->analyze($message);

            $pars[] = array( 'message' => $message, 'module' => 'default', 'rule' => '-1', );
            $hitParam['rule'] = -2;
            $hitParam['module'] = '';
            $hitParam['message'] = $message;

            $hitKeyword = array();
            $response = array();

            foreach ($pars as $par) {
                if (empty( $par['module'] )) {
                    continue;
                }
                $par['message'] = $message;
                $response = $this->process($par);
                if ($this->isValidResponse($response)) {
                    $hitParam = $par;
                    if (!empty( $par['keyword'] )) {
                        $hitKeyword = $par['keyword'];
                    }
                    break;
                }
            }
            $response_debug = $response;
            $pars_debug = $pars;
            if ($hitParam['module'] == 'default' && is_array($response) && is_array($response['params'])) {
                foreach ($response['params'] as $par) {
                    if (empty( $par['module'] )) {
                        continue;
                    }
                    $response = $this->process($par);
                    if ($this->isValidResponse($response)) {
                        $hitParam = $par;
                        if (!empty( $par['keyword'] )) {
                            $hitKeyword = $par['keyword'];
                        }
                        break;
                    }
                }
            }
            WeUtility::logging('params', var_export($hitParam, true));
            WeUtility::logging('response', $response);
            $resp = $this->account->response($response);
            if (!empty( $_GET['encrypt_type'] ) && $_GET['encrypt_type'] == 'aes') {
                $resp = $this->account->encryptMsg($resp);
                $resp = $this->account->xmlDetract($resp);
            }
            if ($_W['debug']) {
                $_W['debug_data'] = array( 'resp' => $resp, 'is_default' => 0, );
                if (count($pars_debug) == 1) {
                    $_W['debug_data']['is_default'] = 1;
                    $_W['debug_data']['params'] = $response_debug['params'];
                } else {
                    array_pop($pars_debug);
                    $_W['debug_data']['params'] = $pars_debug;
                }
                $_W['debug_data']['hitparam'] = $hitParam;
                $_W['modules']['cover'] = array( 'title' => '入口封面', 'name' => 'cover', );

                load()->web('template');
                $process = template('utility/emulator', TEMPLATE_FETCH);
                echo json_encode(array( 'resp' => $resp, 'process' => $process, ));
                exit();
            }
            $mapping = array( '[from]' => $this->message['from'], '[to]' => $this->message['to'], '[rule]' => $this->params['rule'], );
            $resp = str_replace(array_keys($mapping), array_values($mapping), $resp);
            ob_start();
            echo $resp;
            ob_start();
            $this->receive($hitParam, $hitKeyword, $response);
            ob_end_clean();
            exit();
        }
        WeUtility::logging('waring', 'Request Failed');
        exit( 'Request Failed' );
    }

    private function isValidResponse($response){
        if (is_array($response)) {
            if ($response['type'] == 'text' && !empty( $response['content'] )) {
                return true;
            }
            if ($response['type'] == 'news' && !empty( $response['items'] )) {
                return true;
            }
            if (!in_array($response['type'], array( 'text', 'news', 'image', ))) {
                return true;
            }
        }

        return false;
    }


    private function booking($message){
        global $_W;
        if ($message['event'] == 'unsubscribe' || $message['event'] == 'subscribe') {
            $todaystat = pdo_get('stat_fans', array( 'date' => date('Ymd'), 'uniacid' => $_W['uniacid'], ));
            if ($message['event'] == 'unsubscribe') {
                if (empty( $todaystat )) {
                    $updatestat = array( 'new' => 0, 'uniacid' => $_W['uniacid'], 'cancel' => 1, 'cumulate' => 0, 'date' => date('Ymd'), );
                    pdo_insert('stat_fans', $updatestat);
                } else {
                    $updatestat = array( 'cancel' => $todaystat['cancel'] + 1, );
                    $updatestat['cumulate'] = 0;
                    pdo_update('stat_fans', $updatestat, array( 'id' => $todaystat['id'] ));
                }
            } elseif ($message['event'] == 'subscribe') {
                if (empty( $todaystat )) {
                    $updatestat = array( 'new' => 1, 'uniacid' => $_W['uniacid'], 'cancel' => 0, 'cumulate' => 0, 'date' => date('Ymd'), );
                    pdo_insert('stat_fans', $updatestat);
                } else {
                    $updatestat = array( 'new' => $todaystat['new'] + 1, 'cumulate' => 0, );
                    pdo_update('stat_fans', $updatestat, array( 'id' => $todaystat['id'] ));
                }
            }
        }

        load()->model('mc');
        $setting = uni_setting($_W['uniacid'], array( 'passport' ));
        $fans = mc_fansinfo($message['from']);
        $default_groupid = cache_load("defaultgroupid:{$_W['uniacid']}");
        if (empty( $default_groupid )) {
            $default_groupid = pdo_fetchcolumn('SELECT groupid FROM ' . tablename('mc_groups') . ' WHERE uniacid = :uniacid AND isdefault = 1', array( ':uniacid' => $_W['uniacid'] ));
            cache_write("defaultgroupid:{$_W['uniacid']}", $default_groupid);
        }
        if (!empty( $fans )) {
            if ($message['event'] == 'unsubscribe') {
                pdo_update('mc_mapping_fans', array( 'follow' => 0, 'unfollowtime' => TIMESTAMP, ), array( 'fanid' => $fans['fanid'] ));
            } elseif ($message['event'] != 'ShakearoundUserShake' && $message['type'] != 'trace') {
                $rec = array();
                if (empty( $fans['follow'] )) {
                    $rec['follow'] = 1;
                    $rec['followtime'] = $message['time'];
                    $rec['unfollowtime'] = 0;
                }
                $member = array();
                if (!empty( $fans['uid'] )) {
                    $member = mc_fetch($fans['uid']);
                }
                if (empty( $member )) {
                    if (!isset( $setting['passport'] ) || empty( $setting['passport']['focusreg'] )) {
                        $data = array( 'uniacid' => $_W['uniacid'], 'email' => md5($message['from']) . '@we7.cc', 'salt' => random(8), 'groupid' => $default_groupid, 'createtime' => TIMESTAMP, );
                        $data['password'] = md5($message['from'] . $data['salt'] . $_W['config']['setting']['authkey']);
                        pdo_insert('mc_members', $data);
                        $rec['uid'] = pdo_insertid();
                    }
                }
                if (!empty( $rec )) {
                    pdo_update('mc_mapping_fans', $rec, array( 'openid' => $message['from'], ));
                }
            }
        } else {
            if ($message['event'] == 'subscribe' || $message['event'] == 'user_get_card' || $message['type'] == 'text' || $message['type'] == 'image') {
                $rec = array();
                $rec['acid'] = $_W['acid'];
                $rec['uniacid'] = $_W['uniacid'];
                $rec['uid'] = 0;
                $rec['openid'] = $message['from'];
                $rec['salt'] = random(8);
                $rec['follow'] = 1;
                $rec['followtime'] = $message['time'];
                $rec['unfollowtime'] = 0;
                if (!isset( $setting['passport'] ) || empty( $setting['passport']['focusreg'] )) {
                    $data = array( 'uniacid' => $_W['uniacid'], 'email' => md5($message['from']) . '@we7.cc', 'salt' => random(8), 'groupid' => $default_groupid, 'createtime' => TIMESTAMP, );
                    $data['password'] = md5($message['from'] . $data['salt'] . $_W['config']['setting']['authkey']);
                    pdo_insert('mc_members', $data);
                    $rec['uid'] = pdo_insertid();
                }
                pdo_insert('mc_mapping_fans', $rec);
            }
        }
    }

    private function receive($par, $keyword, $response){
        global $_W;
        $subscribe = cache_load('module_receive_enable');
        $modules = uni_modules();
        $obj = WeUtility::createModuleReceiver('core');
        $obj->message = $this->message;
        $obj->params = $par;
        $obj->response = $response;
        $obj->keyword = $keyword;
        $obj->module = 'core';
        $obj->uniacid = $_W['uniacid'];
        $obj->acid = $_W['acid'];
        if (method_exists($obj, 'receive')) {
            @$obj->receive();
        }
        if (!empty( $subscribe['subscribe'] ) && ( $this->message['event'] == 'subscribe' || $this->message['type'] == 'subscribe' )) {
            foreach ($subscribe['subscribe'] as $modulename) {
                $obj = WeUtility::createModuleReceiver($modulename);
                $obj->message = $this->message;
                $obj->params = $par;
                $obj->response = $response;
                $obj->keyword = $keyword;
                $obj->module = $modules[$modulename];
                $obj->uniacid = $_W['uniacid'];
                $obj->acid = $_W['acid'];
                if (method_exists($obj, 'receive')) {
                    @$obj->receive();
                }
            }
        } elseif (!empty( $subscribe['unsubscribe'] ) && ( $this->message['event'] == 'unsubscribe' || $this->message['type'] == 'unsubscribe' )) {
            foreach ($subscribe['unsubscribe'] as $modulename) {
                $obj = WeUtility::createModuleReceiver($modulename);
                $obj->message = $this->message;
                $obj->params = $par;
                $obj->response = $response;
                $obj->keyword = $keyword;
                $obj->module = $modules[$modulename];
                $obj->uniacid = $_W['uniacid'];
                $obj->acid = $_W['acid'];
                if (method_exists($obj, 'receive')) {
                    @$obj->receive();
                }
            }
        } elseif (!empty( $subscribe['user_get_card'] ) && $this->message['event'] == 'user_get_card') {
            foreach ($subscribe['user_get_card'] as $modulename) {
                $obj = WeUtility::createModuleReceiver($modulename);
                $obj->message = $this->message;
                $obj->params = $par;
                $obj->response = $response;
                $obj->keyword = $keyword;
                $obj->module = $modules[$modulename];
                $obj->uniacid = $_W['uniacid'];
                $obj->acid = $_W['acid'];
                if (method_exists($obj, 'receive')) {
                    @$obj->receive();
                }
            }
        } elseif (!empty( $subscribe['user_consume_card'] ) && $this->message['event'] == 'user_consume_card') {
            foreach ($subscribe['user_consume_card'] as $modulename) {
                $obj = WeUtility::createModuleReceiver($modulename);
                $obj->message = $this->message;
                $obj->params = $par;
                $obj->response = $response;
                $obj->keyword = $keyword;
                $obj->module = $modules[$modulename];
                $obj->uniacid = $_W['uniacid'];
                $obj->acid = $_W['acid'];
                if (method_exists($obj, 'receive')) {
                    @$obj->receive();
                }
            }
        } else {
            $modules = $subscribe[$this->message['type']];
            if (!empty( $modules )) {
                foreach ($modules as $modulename) {
                    $row = array();
                    $row['uniacid'] = $_W['uniacid'];
                    $row['acid'] = $_W['acid'];
                    $row['dateline'] = $_W['timestamp'];
                    $row['message'] = iserializer($this->message);
                    $row['keyword'] = iserializer($keyword);
                    $row['params'] = iserializer($par);
                    $row['response'] = iserializer($response);
                    $row['module'] = $modulename;
                    $row['type'] = 1;
                    pdo_insert('core_queue', $row);
                }
            }
            if (date('N') == '1') {
                pdo_query("DELETE FROM " . tablename('core_queue') . " WHERE dateline < '" . ( $_W['timestamp'] - 2592000 ) . "'");
            }
        }
    }


    private function analyze(&$message){
        global $_W;
        $params = array();
        if (in_array($message['type'], array( 'event', 'qr', ))) {
            $params = call_user_func_array(array( $this, 'analyze' . $message['type'], ), array( &$message ));

            //$this->analyzeCoupon($message);

            if (!empty( $params )) {
                return (array)$params;
            }

        }
        if (!empty( $_SESSION['__contextmodule'] ) && in_array($_SESSION['__contextmodule'], $this->modules)) {
            if ($_SESSION['__contextexpire'] > TIMESTAMP) {
                $params[] = array( 'message' => $message, 'module' => $_SESSION['__contextmodule'], 'rule' => $_SESSION['__contextrule'], 'priority' => $_SESSION['__contextpriority'], 'context' => true, );

                return $params;
            } else {
                unset( $_SESSION );
                session_destroy();
            }
        }

        if (method_exists($this, 'analyze' . $message['type'])) {
            $temp = call_user_func_array(array( $this, 'analyze' . $message['type'], ), array( &$message ));
            if (!empty( $temp ) && is_array($temp)) {
                $params += $temp;
            }
        } else {
            $params += $this->handler($message['type']);
        }

        return $params;
    }

    private function analyzeSubscribe(&$message){
        global $_W;
        $params = array();
        $message['type'] = 'text';
        $message['redirection'] = true;
        if (!empty( $message['scene'] )) {
            $message['source'] = 'qr';
            $sceneid = trim($message['scene']);
            $scene_condition = '';
            if (is_numeric($sceneid)) {
                $scene_condition = " `qrcid` = '{$sceneid}'";
            } else {
                $scene_condition = " `scene_str` = '{$sceneid}'";
            }
            $qr = pdo_fetch("SELECT `id`, `keyword` FROM " . tablename('qrcode') . " WHERE {$scene_condition} AND `uniacid` = '{$_W['uniacid']}'");
            if (!empty( $qr )) {
                $message['content'] = $qr['keyword'];
                $params += $this->analyzeText($message);

                return $params;
            }
        }
        $message['source'] = 'subscribe';
        $setting = uni_setting($_W['uniacid'], array( 'welcome' ));
        if (!empty( $setting['welcome'] )) {
            $message['content'] = $setting['welcome'];
            $params += $this->analyzeText($message);
        }

        return $params;
    }

    private function analyzeQR(&$message){
        global $_W;
        $params = array();
        $message['type'] = 'text';
        $message['redirection'] = true;
        if (!empty( $message['scene'] )) {
            $message['source'] = 'qr';
            $sceneid = trim($message['scene']);
            $scene_condition = '';
            if (is_numeric($sceneid)) {
                $scene_condition = " `qrcid` = '{$sceneid}'";
            } else {
                $scene_condition = " `scene_str` = '{$sceneid}'";
            }
            $qr = pdo_fetch("SELECT `id`, `keyword` FROM " . tablename('qrcode') . " WHERE {$scene_condition} AND `uniacid` = '{$_W['uniacid']}'");
            if (!empty( $qr )) {
                $message['content'] = $qr['keyword'];
                $params += $this->analyzeText($message);
            }
        }

        return $params;
    }

    public function analyzeText(&$message, $order = 0){
        global $_W;

        $pars = array();

        $order = intval($order);
        if (!isset( $message['content'] )) {
            return $pars;
        }

        $condition = <<<EOF
`uniacid` IN ( 0, {$_W['uniacid']} )
AND 
(
	( `type` = 1 AND `content` = :c1 )
	or
	( `type` = 2 AND instr(:c2, `content`) )
	or
	( `type` = 3 AND :c3 REGEXP `content` )
	or
	( `type` = 4 )
)
AND `status`=1
EOF;

        $params = array();
        $params[':c1'] = $message['content'];
        $params[':c2'] = $message['content'];
        $params[':c3'] = $message['content'];

        if (intval($order) > 0) {
            $condition .= " AND `displayorder` > :order";
            $params[':order'] = $order;
        }

        $keywords = reply_keywords_search($condition, $params);

        if (empty( $keywords )) {
            return $pars;
        }
        foreach ($keywords as $keyword) {
            $params = array( 'message' => $message, 'module' => $keyword['module'], 'rule' => $keyword['rid'], 'priority' => $keyword['displayorder'], 'keyword' => $keyword, );
            $pars[] = $params;
        }

        return $pars;
    }

    private function analyzeEvent(&$message){
        if (strtolower($message['event']) == 'subscribe') {
            return $this->analyzeSubscribe($message);
        }
        if (strtolower($message['event']) == 'click') {
            $message['content'] = strval($message['eventkey']);

            return $this->analyzeClick($message);
        }
        if (in_array($message['event'], array( 'pic_photo_or_album', 'pic_weixin', 'pic_sysphoto', ))) {
            pdo_query("DELETE FROM " . tablename('menu_event') . " WHERE createtime < '" . ( $GLOBALS['_W']['timestamp'] - 100 ) . "' OR openid = '{$message['from']}'");
            if (!empty( $message['sendpicsinfo']['count'] )) {
                foreach ($message['sendpicsinfo']['piclist'] as $item) {
                    pdo_insert('menu_event', array( 'uniacid' => $GLOBALS['_W']['uniacid'], 'keyword' => $message['eventkey'], 'type' => $message['event'], 'picmd5' => $item, 'openid' => $message['from'], 'createtime' => TIMESTAMP, ));
                }
            } else {
                pdo_insert('menu_event', array( 'uniacid' => $GLOBALS['_W']['uniacid'], 'keyword' => $message['eventkey'], 'type' => $message['event'], 'picmd5' => $item, 'openid' => $message['from'], 'createtime' => TIMESTAMP, ));
            }
            $message['content'] = strval($message['eventkey']);
            $message['source'] = $message['event'];

            return $this->analyzeText($message);
        }
        if (!empty( $message['eventkey'] )) {
            $message['content'] = strval($message['eventkey']);
            $message['type'] = 'text';
            $message['redirection'] = true;
            $message['source'] = $message['event'];

            return $this->analyzeText($message);
        }

        return $this->handler($message['event']);
    }

    private function analyzeClick(&$message){
        if (!empty( $message['content'] ) || $message['content'] !== '') {
            $message['type'] = 'text';
            $message['redirection'] = true;
            $message['source'] = 'click';

            return $this->analyzeText($message);
        }

        return array();
    }

    private function analyzeImage(&$message){
        load()->func('communication');
        if (!empty( $message['picurl'] )) {
            $response = ihttp_get($message['picurl']);
            if (!empty( $response )) {
                $md5 = md5($response['content']);
                $event = pdo_fetch("SELECT keyword, type FROM " . tablename('menu_event') . " WHERE picmd5 = '$md5'");
                if (!empty( $event['keyword'] )) {
                    pdo_delete('menu_event', array( 'picmd5' => $md5 ));
                } else {
                    $event = pdo_fetch("SELECT keyword, type FROM " . tablename('menu_event') . " WHERE openid = '{$message['from']}'");
                }
                if (!empty( $event )) {
                    $message['content'] = $event['keyword'];
                    $message['eventkey'] = $event['keyword'];
                    $message['type'] = 'text';
                    $message['event'] = $event['type'];
                    $message['redirection'] = true;
                    $message['source'] = $event['type'];

                    return $this->analyzeText($message);
                }
            }

            return $this->handler('image');
        }
    }

    private function analyzeVoice(&$message){
        $params = $this->handler('voice');
        if (empty( $params ) && !empty( $message['recognition'] )) {
            $message['type'] = 'text';
            $message['redirection'] = true;
            $message['source'] = 'voice';
            $message['content'] = $message['recognition'];

            return $this->analyzeText($message);
        } else {
            return $params;
        }
    }

    public function analyzeCoupon(&$message){
        global $_W;
        $data = array();
        if ($message['event'] == 'poi_check_notify') {
            $data['status'] = ( $message['result'] == 'succ' ) ? 1 : 3;
            $data['location_id'] = trim($message['poiid']);
            $data['message'] = trim($message['msg']);
            $id = intval($message['uniqid']);
            pdo_update('activity_stores', $data, array( 'id' => $id, 'uniacid' => $_W['uniacid'], ));
        } elseif (in_array($message['event'], array( 'card_pass_check', 'card_not_pass_check', ))) {
            $data['status'] = ( $message['event'] == 'card_pass_check' ) ? 3 : 2;
            $card_id = trim($message['cardid']);
            $is_exist = pdo_getcolumn('coupon', array( 'card_id' => $card_id ), 'id');
            if (!empty( $is_exist )) {
                pdo_update('coupon', $data, array( 'card_id' => $card_id ));
            }else{
                // 会员卡
                $this->analyzeCard($message);
            }
        } elseif ($message['event'] == 'user_get_card') {
            load()->model('activity');

            $is_exist = pdo_getcolumn('coupon', array( 'card_id' => trim($message['cardid'])), 'id');

            if($is_exist){
                if (empty( $message['isgivebyfriend'] )) {
                    $coupon_record = pdo_get('coupon_record', array( 'card_id' => trim($message['cardid']), 'openid' => trim($message['fromusername']), 'status' => '1', 'code' => '', ), array( 'id' ));
                    if (!empty( $coupon_record )) {
                        pdo_update('coupon_record', array( 'code' => trim($message['usercardcode']) ), array( 'id' => $coupon_record['id'] ));
                    } else {
                        $qrcode_info = pdo_get('qrcode', array( 'qrcid' => $message['outerid'] ));
                        if (!empty( $qrcode_info )) {
                            $fans_info = mc_fansinfo($message['fromusername']);
                            $coupon_info = pdo_get('coupon', array( 'card_id' => $message['cardid'] ));
                            $pcount = pdo_fetchcolumn("SELECT count(*) FROM " . tablename('coupon_record') . " WHERE `openid` = :openid AND `couponid` = :couponid", array( ':couponid' => $coupon_info['id'], ':openid' => trim($message['fromusername']), ));
                            if ($pcount < $coupon_info['get_limit'] && $coupon_info['quantity'] > 0) {
                                $insert_data = array( 'uniacid' => $qrcode_info['uniacid'], 'card_id' => $message['cardid'], 'openid' => $message['fromusername'], 'code' => $message['usercardcode'], 'addtime' => TIMESTAMP, 'status' => '1', 'uid' => $fans_info['uid'], 'remark' => '用户通过投放扫码', 'couponid' => $coupon_info['id'], );
                                pdo_insert('coupon_record', $insert_data);
                                pdo_update('coupon', array( 'quantity' => $coupon_info['quantity'] - 1, 'dosage' => $coupon_info['dosage'] + 1, ), array( 'uniacid' => $qrcode_info['uniacid'], 'id' => $coupon_info['id'], ));
                            }
                        }
                    }
                } else {
                    $old_record = pdo_get('coupon_record', array( 'openid' => trim($message['friendusername']), 'card_id' => trim($message['cardid']), 'code' => trim($message['oldusercardcode']), ));
                    pdo_update('coupon_record', array( 'addtime' => TIMESTAMP, 'givebyfriend' => intval($message['isgivebyfriend']), 'openid' => trim($message['fromusername']), 'code' => trim($message['usercardcode']), 'status' => '1', ), array( 'id' => $old_record['id'] ));
                }
            }else{
                $this->analyzeCard($message);
            }

            $this->receive();
        } elseif ($message['event'] == 'user_del_card') {
            $card_id = trim($message['cardid']);
            $openid = trim($message['fromusername']);
            $code = trim($message['usercardcode']);
            $is_exist = pdo_getcolumn('coupon', array( 'card_id' => $card_id ), 'id');
            if (!empty( $is_exist )) {
                pdo_update('coupon_record', array( 'status' => 4 ), array( 'acid' => $_W['acid'], 'card_id' => $card_id, 'openid' => $openid, 'code' => $code, ));
            }else{
                // 会员卡
                $this->analyzeCard($message);
                exit();
            }
        } elseif ($message['event'] == 'user_consume_card') {
            $card_id = trim($message['cardid']);
            $openid = trim($message['fromusername']);
            $code = trim($message['usercardcode']);
            pdo_update('coupon_record', array( 'status' => 3 ), array( 'acid' => $_W['acid'], 'card_id' => $card_id, 'openid' => $openid, 'code' => $code, ));
            $this->receive();
        }
        exit( 'success' );
    }


    public function analyzeCard(&$message){
        global $_W;

        if(in_array($message['event'], array( 'card_pass_check', 'card_not_pass_check', ))){
            $data['status'] = ( $message['event'] == 'card_pass_check' ) ? 3 : 2;
            $card_id = trim($message['cardid']);

            $is_exist = pdo_getcolumn('member_wechat_card', array( 'card_id' => $card_id ), 'id');
            if (!empty( $is_exist )) {
                pdo_update('member_wechat_card', $data, array( 'card_id' => $card_id ));
            }
        }

        if($message['event'] == 'user_get_card'){

            $record_info = pdo_get('wechat_card_record', array('card_id' => $message['cardid'], 'openid' => $message['fromusername'], 'code' => $message['usercardcode']));

            if(empty($record_info)){
                $card_info = pdo_get('member_wechat_card', array( 'card_id' => $message['cardid'] ));
                pdo_update('member_wechat_card', array(  'dosage +=' => 1 ), array( 'uniacid' => $card_info['uniacid'], 'id' => $card_info['id'], ));

                $fans_info = mc_fansinfo($message['fromusername']);
                $insert_data = array( 'uniacid' => $card_info['uniacid'], 'card_id' => $message['cardid'], 'openid' => $message['fromusername'], 'code' => $message['usercardcode'], 'addtime' => TIMESTAMP, 'status' => 1, 'uid' => $fans_info['uid'], 'remark' => '用户通过投放扫码领取');

                pdo_insert('wechat_card_record', $insert_data);
            }else{
                if(!empty($message['isrestoremembercard'])){
                    load()->classs('coupon');
                    $coupon_api = new coupon();
                    $userInfo = $coupon_api->getUserInfo($message['cardid'], $message['usercardcode']);

                    $infoTemp = $userInfo['user_info']['common_field_list'];
                    $info = array();

                    foreach($infoTemp as $item){
                        switch($item['name']){
                            case 'USER_FORM_INFO_FLAG_MOBILE' :
                                $info['mobile'] = $item['value'];
                                break;
                            case 'USER_FORM_INFO_FLAG_NAME' :
                                $info['realname'] = $item['value'];
                                break;
                        }
                    }

                    $info['sex'] = $userInfo['sex'] == 'MALE' ? 1 : 0;
                    $info['extra'] = iserializer($userInfo['user_info']);
                    $info['status'] = 1;

                    pdo_update('wechat_card_record', $info, array('card_id' => $message['cardid'], 'openid' => $message['fromusername'], 'code' => $message['usercardcode']));
                }
            }

            $this->receive();
        }

        // submit_membercard_user_info 激活信息提交。
        if ($message['event'] == 'submit_membercard_user_info') {
            load()->classs('coupon');
            $coupon_api = new coupon();

            $userInfo = $coupon_api->getUserInfo($message['cardid'], $message['usercardcode']);

            $infoTemp = $userInfo['user_info']['common_field_list'];
            $info = array();

            if(!empty($infoTemp)){
                foreach($infoTemp as $item){
                    switch($item['name']){
                        case 'USER_FORM_INFO_FLAG_MOBILE' :
                            $info['mobile'] = $item['value'];
                            break;
                        case 'USER_FORM_INFO_FLAG_NAME' :
                            $info['realname'] = $item['value'];
                            break;
                    }
                }
            }

            $info['sex'] = $userInfo['sex'] == 'MALE' ? 1 : 0;
            $info['extra'] = iserializer($userInfo['user_info']);

            $card_info = pdo_get('member_wechat_card', array( 'card_id' => $message['cardid'] ));
            $record_info = pdo_get('wechat_card_record', array('card_id' => $message['cardid'], 'openid' => $message['fromusername'], 'code' => $message['usercardcode']));


            if($record_info['status'] == 1){
                // 更新用户领卡状态
                $info['status'] = 2;
                pdo_update('wechat_card_record', $info, array('card_id' => $message['cardid'], 'openid' => $message['fromusername'], 'code' => $message['usercardcode']));

                // 同步系统信息（当前仅同步姓名与手机号）
                mc_update($message['fromusername'], array('realname' => $info['realname'], 'mobile' => $info['mobile']));


                if(!empty($card_info['supply_bonus']) || !empty($card_info['supply_balance'])){
                    $coupon = new MemberCard();

                    // 首次激活赠送积分
                    $bonus_rule = iunserializer($card_info['bonus_rule']);

                    if(!empty($bonus_rule['init_increase_bonus'])){
                        // 设置需要更新的积分数据
                        $coupon->setRecordBonus($bonus_rule['init_increase_bonus'], '激活时赠送积分');
                    }

                    // 设置需要更新的余额数据
                    $coupon->setRecordBalance(0, '激活时同步余额');

                    // 提交更新（updateUser 方法 第三个参数，将决定是否同步至微信会员卡。）
                    $coupon->updateUser($message['fromusername'], $message['cardid'], $message['usercardcode']);
                }

            }else{
                pdo_update('wechat_card_record', $info, array('id' => $record_info['id']));

                // 同步系统信息（当前仅同步姓名与手机号）
                mc_update($message['fromusername'], array('realname' => $info['realname'], 'mobile' => $info['mobile']));
            }
            // TODO : 添加额外的需求

        }

        if ($message['event'] == 'user_del_card') {
            $card_id = trim($message['cardid']);
            $openid = trim($message['fromusername']);
            $code = trim($message['usercardcode']);

            $card_info = pdo_get('member_wechat_card', array( 'card_id' => $message['cardid'] ));

            if (!empty( $card_info )) {
                pdo_update('wechat_card_record', array( 'status' => 0 ), array( 'uniacid' => $card_info['uniacid'], 'card_id' => $card_id, 'openid' => $openid, 'code' => $code, ));
            }
        }

    }

    private function handler($type){
        if (empty( $type )) {
            return array();
        }
        global $_W;
        $params = array();
        $setting = uni_setting($_W['uniacid'], array( 'default_message' ));
        $df = $setting['default_message'];
        if (is_array($df) && isset( $df[$type] )) {
            if (!empty( $df[$type]['type'] ) && $df[$type]['type'] == 'keyword') {
                $message = $this->message;
                $message['type'] = 'text';
                $message['redirection'] = true;
                $message['source'] = $type;
                $message['content'] = $df[$type]['keyword'];

                return $this->analyzeText($message);
            } else {
                $params[] = array( 'message' => $this->message, 'module' => $df[$type]['module'], 'rule' => '-1', );

                return $params;
            }
        }

        return array();
    }


    private function process($param){
        global $_W;
        if (empty( $param['module'] ) || !in_array($param['module'], $this->modules)) {
            return false;
        }

        $processor = WeUtility::createModuleProcessor($param['module']);
        $processor->message = $param['message'];
        $processor->rule = $param['rule'];
        $processor->priority = intval($param['priority']);
        $processor->inContext = $param['context'] === true;
        $response = $processor->respond();
        if (empty( $response )) {
            return false;
        }

        return $response;
    }


    public function died($content = ''){
        global $_W, $engine;
        if (empty( $content )) {
            exit( '' );
        }
        $response['FromUserName'] = $engine->message['to'];
        $response['ToUserName'] = $engine->message['from'];
        $response['MsgType'] = 'text';
        $response['Content'] = htmlspecialchars_decode($content);
        $response['CreateTime'] = TIMESTAMP;
        $response['FuncFlag'] = 0;
        $xml = array2xml($response);
        if (!empty( $_GET['encrypt_type'] ) && $_GET['encrypt_type'] == 'aes') {
            $resp = $engine->account->encryptMsg($xml);
            $resp = $engine->account->xmlDetract($resp);
        } else {
            $resp = $xml;
        }
        exit( $resp );
    }
}


